package top.yueyazhui.dds.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import top.yueyazhui.dds.annotation.DataSource;
import top.yueyazhui.dds.datasource.DynamicDataSourceContextHolder;

@Component
@Aspect
@Order(2)
public class DataSourceAspect {

    /**
     * @annotation(top.yueyazhui.dds.annotation.DataSource) 表示如果方法上有 @DataSource 注解的就将方法拦截下来
     * @within(top.yueyazhui.dds.annotation.DataSource) 表示如果方法的类上有 @DataSource 注解的就将方法拦截下来
     */
    @Pointcut("@annotation(top.yueyazhui.dds.annotation.DataSource) || @within(top.yueyazhui.dds.annotation.DataSource)")
    public void pointcut() {

    }

    @Around("pointcut()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) {
        // 获取方法上面的有效注解
        DataSource dataSource = getDataSource(proceedingJoinPoint);
        if (dataSource != null) {
            // 获取注解中数据源的名称
            String value = dataSource.value();
            DynamicDataSourceContextHolder.setDataSource(value);
        }
        try {
            return proceedingJoinPoint.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        } finally {
            DynamicDataSourceContextHolder.removeDataSource();
        }
        return null;
    }

    private DataSource getDataSource(ProceedingJoinPoint proceedingJoinPoint) {
        MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
        // 查找方法上的注解
        DataSource annotation = AnnotationUtils.findAnnotation(signature.getMethod(), DataSource.class);
        if (annotation != null) {
            // 说明方法上有 @DataSource 注解，返回方法上的 @DataSource 注解
            return annotation;
        }
        // 返回类上的 @DataSource 注解
        return AnnotationUtils.findAnnotation(signature.getDeclaringType(), DataSource.class);
    }
}
